#include "StdAfx.h"
#include <core/Debug.h>
#include "../sgp/TimerManager.h"

namespace ja2{ namespace sgp
{
	TimerManager::TimerManager()
		: m_PauseClock(false), m_NoPauseClock(0), m_Clock(0)
	{
		// First get timer resolutions
		TIMECAPS time_caps;
		if(timeGetDevCaps(&time_caps, sizeof(time_caps)) != TIMERR_NOERROR )
			JA2_DEBUG_MESSAGE(TOPIC_JA2, DebugManager::DL_3, resources::COULD_NOT_GET_TIMER_INFO);
		// Initialize timer map
		for(int i = 0; i < TT_END; ++i)
			m_TimerMap[static_cast<TimerType>(i)] = get_interval(static_cast<TimerType>(i));
		// Set timer at lowest resolution. Could use middle of lowest/highest, we'll see how this performs first
		m_TimerId = timeSetEvent(BASE_TIME_SLICE, BASE_TIME_SLICE, reinterpret_cast<LPTIMECALLBACK>(timer_callback), reinterpret_cast<DWORD_PTR>(this), TIME_PERIODIC | TIME_KILL_SYNCHRONOUS | TIME_CALLBACK_FUNCTION);
		if (!m_TimerId)
		{
			JA2_DEBUG_MESSAGE( TOPIC_JA2, DebugManager::DL_3, resources::COULD_NOT_CREATE_TIMER);
			throw RuntimeException(resources::COULD_NOT_CREATE_TIMER);
		}
		
	}


	TimerManager::~TimerManager()
	{
		timeKillEvent(m_TimerId);
	}

	std::uint_least32_t TimerManager::get_interval(TimerType Type)
	{
		std::uint_least32_t ret;

		switch(Type)
		{
		case TT_OVERHEAD:
			ret = 5;
			break;
		case TT_NEXT_SCROLL:
			ret = 20;
			break;
		case TT_START_SCROLL:
			ret = 200;
			break;
		case TT_ANIMATE_TILES:
			ret = 200;
			break;
		case TT_FPS_COUNTER:
			ret = 1000;
			break;
		case TT_PATH_FIND_COUNTER:
			ret = 80;
			break;
		case TT_CURSOR_COUNTER:
			ret = 150;
			break;
		case TT_RMOUSE_CLICK_DELAY_COUNTER:
			ret = 250;
			break;
		case TT_LMOUSE_CLICK_DELAY_COUNTER:
			ret = 300;
			break;
		case TT_SLIDE_TEXT:
			ret = 30;
			break;
		case TT_TARGET_REFINE:
			ret = 200;
			break;
		case TT_CURSOR_FLASH:
			ret = 150;
			break;
		case TT_FADE_GUY_OUT:
			ret = 60;
			break;
		case TT_PANEL_SLIDE_UNUSED:
			ret = 160;
			break;
		case TT_CLOCK_UPDATE:
			ret = 1000;
			break;
		case TT_PHYSICS_UPDATE:
			ret = 20;
			break;
		case TT_GLOW_ENEMIES:
			ret = 100;
			break;
		case TT_STRATEGIC_OVERHEAD:
			ret = 20;
			break;
		case TT_CYCLE_RENDER_ITEMCOLOR:
			ret = 40;
			break;
		case TT_NON_GUN_TARGET_REFINE:
			ret = 500;
			break;
		case TT_CURSOR_FLASH_UPDATE:
			ret = 250;
			break;
		case TT_INVALID_AP_HOLD:
			ret = 500;
			break;
		case TT_RADAR_MAP_BLINK:
			ret = 400;
			break;
		case TT_OVERHEAD_MAP_BLINK:
			ret = 400;
			break;
		case TT_MUSIC_OVERHEAD:
			ret = 10;
			break;
		case TT_RUBBER_BAND_START_DELAY:
			ret = 100;
			break;
		default:
			throw RuntimeException("Unknown timer type for interval");
			break;
		}

		return ret;
	}

	void TimerManager::timer_callback(UINT /*TimerID*/, UINT /*Msg*/, DWORD_PTR pUser, DWORD_PTR /*dw1*/, DWORD_PTR /*dw2*/)
	{
		static bool is_in_function = false;
		if (!is_in_function)
		{
			is_in_function = true;
			// Get the instance
			TimerManager &instance = *reinterpret_cast<TimerManager *>(pUser);
			// Update base clock
			instance.m_NoPauseClock += BASE_TIME_SLICE;
			// Clock not paused
			if (!instance.m_PauseClock)
			{
				// Update clock
				instance.m_Clock += BASE_TIME_SLICE;
				// Update all counters
				for(auto it = instance.m_TimerMap.begin(), end = instance.m_TimerMap.end(); it != end; ++it)
					instance.update_counter(it->first);
				// Update some specialized countdown timers...
//				UPDATETIMECOUNTER( giTimerAirRaidQuote );
//				UPDATETIMECOUNTER( giTimerAirRaidDiveStarted );
//				UPDATETIMECOUNTER( giTimerAirRaidUpdate );
//				UPDATETIMECOUNTER( giTimerTeamTurnUpdate );
//
//				if ( gpCustomizableTimerCallback )
//				{
//					UPDATETIMECOUNTER( giTimerCustomizable );
//				}
//				// If mapscreen...
//				if( guiTacticalInterfaceFlags & INTERFACE_MAPSCREEN )
//				{
//					// IN Mapscreen, loop through player's team.....
//					for ( gCNT = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; gCNT <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; gCNT++ )
//					{
//						gPSOLDIER = MercPtrs[ gCNT ];
//						UPDATETIMECOUNTER( gPSOLDIER->timeCounters.PortraitFlashCounter );
//						UPDATETIMECOUNTER( gPSOLDIER->timeCounters.PanelAnimateCounter );
//					}
//				}
//				else
//				{
//					// Set update flags for soldiers
//					////////////////////////////
//					for ( gCNT = 0; gCNT < guiNumMercSlots; gCNT++ )
//					{
//						gPSOLDIER = MercSlots[ gCNT ];
//
//						if ( gPSOLDIER != NULL )
//						{
//							UPDATETIMECOUNTER( gPSOLDIER->timeCounters.UpdateCounter );
//							UPDATETIMECOUNTER( gPSOLDIER->timeCounters.DamageCounter );
//							UPDATETIMECOUNTER( gPSOLDIER->timeCounters.ReloadCounter );
//							UPDATETIMECOUNTER( gPSOLDIER->timeCounters.FlashSelCounter );
//							UPDATETIMECOUNTER( gPSOLDIER->timeCounters.BlinkSelCounter );
//							UPDATETIMECOUNTER( gPSOLDIER->timeCounters.PortraitFlashCounter );
//							UPDATETIMECOUNTER( gPSOLDIER->timeCounters.AICounter );
//							UPDATETIMECOUNTER( gPSOLDIER->timeCounters.FadeCounter );
//							UPDATETIMECOUNTER( gPSOLDIER->timeCounters.NextTileCounter );
//							UPDATETIMECOUNTER( gPSOLDIER->timeCounters.PanelAnimateCounter );
//						}
//					}
//				}
//			}
				is_in_function = false;
			}
		}
	}

	void TimerManager::update_counter(TimerType Timer)
	{
		m_TimerMap[Timer] = (m_TimerMap[Timer] - BASE_TIME_SLICE < 0  ?  0  : m_TimerMap[Timer] - BASE_TIME_SLICE);
	}

	std::uint_least32_t TimerManager::get_clock() const
	{
		return m_Clock;
	}
} /*sgp*/} /*ja2*/